home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / source / snip9503 / lld.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-14  |  19.1 KB  |  656 lines

  1. /* =======================================================================
  2.     LLD.c           Generic Doubly Linked Lists for fixed size data.
  3.                     Each List has its own specific data size.
  4.                     This version uses dummy head and dummy tail nodes.
  5.                     Which prevents special handling for the first and last
  6.                     nodes.
  7.  
  8.                     v1.00  94-08-21
  9.  
  10.                     Compile with NDEBUG not defined for debugging version.
  11.                     Compile with NDEBUG defined for production version.
  12.  
  13.                     The node pointers are restricted to valid values.
  14.                     They point only in empty lists to invalid data.
  15.  
  16.                     Possible future enhancements:
  17.                     - List(s) of free nodes for fast node memory alloc.
  18.                     - FindFirst() & FindNext().
  19.                     - Data access via first and/or last node pointers.
  20.                       (duplicate the functions and change .current to
  21.                       .first or .last)
  22.                     - Node deletion via first and/or last node pointers.
  23.                       (as for access functions, then simplify ...)
  24.  
  25.  _____              This version is Public Domain.
  26.  /_|__|             A.Reitsma, Delft, The Netherlands.
  27. /  | \  --------------------------------------------------------------- */
  28.  
  29. #include <stdarg.h>         /* variable arg handling */
  30. #include <assert.h>         /* debugging */
  31. #include "defines.h"        /* debugging incl MALLOC (re-) definition   */
  32. #include "LLD.h"            /* also includes portable.h if necessary    */
  33.  
  34. #define NO_PROBLEMS LIST_NO_PROBLEMS /* local redefinition */
  35.  
  36. struct Node
  37. {
  38.     struct Node * next;
  39.     struct Node * prev;
  40.     int data;               /* also place-holder for larger items.      */
  41. };                          /* actual nodes have various sizes,         */
  42.                             /* but a fixed size within a list.          */
  43. struct ListHead
  44. {
  45.     struct Node * current;  /* points to the actual current node        */
  46.     struct Node * first;    /* always points to dummy head node         */
  47.     struct Node * last;     /* always points to dummy tail node         */
  48.     int itemsize ;          /* zero value: used as 'list not used' flag */
  49. };
  50.  
  51. #define ERR_MEMORY          -1
  52.  
  53. #define NODE_MALLOC(list)   (struct Node *) \
  54.                             MALLOC( ListControl[ list ].itemsize \
  55.                                     + 2 * sizeof( struct Node * ), char )
  56.  
  57. #define NODE_FREE(node)     FREE(node)
  58.  
  59. /* ---- Local data ---------------------------------------------------- */
  60.  
  61. static struct ListHead * ListControl = NULL;
  62. static unsigned int ListCount ;
  63.  
  64. /* ---- LL system mangement ------------------------------------------- */
  65.  
  66. static int ListInit( int List, int ItemSize )
  67. {
  68.     struct Node * Tmp ;
  69.  
  70.     if( 0 != ItemSize )
  71.     {
  72.         /* create dummy head node
  73.         */
  74.         Tmp = NODE_MALLOC( List );
  75.         if( NULL == Tmp )
  76.         {
  77.             return ERR_MEMORY ;
  78.         }
  79.         Tmp->prev = NULL ;     /* NULL identifies it as dummy head node */
  80.         Tmp->data = 0xA709 ;   /* dummy value */
  81.         ListControl[ List ].first = Tmp ;
  82.  
  83.         /* create dummy tail node
  84.         */
  85.         Tmp = NODE_MALLOC( List );
  86.         if( NULL == Tmp )
  87.         {
  88.             NODE_FREE( Tmp );          /* no need to cause memory leaks */
  89.             ListControl[ List ].first = NULL ; /* or other errors       */
  90.             return ERR_MEMORY ;        /* even if we're in trouble ...  */
  91.         }
  92.         Tmp->next = NULL ;     /* NULL identifies it as dummy tail node */
  93.         Tmp->data = 0xA725 ;   /* dummy value */
  94.         Tmp->prev = ListControl[ List ].first ;
  95.  
  96.         ListControl[ List ].current     =
  97.         ListControl[ List ].last        =
  98.         ListControl[ List ].first->next = Tmp ;
  99.     }
  100.     else
  101.     {
  102.         ListControl[ List ].current =
  103.         ListControl[ List ].first   =
  104.         ListControl[ List ].last    = NULL ;
  105.     }
  106.  
  107.     ListControl[ List ].itemsize = ItemSize ; /* zero: list not used    */
  108.     return NO_PROBLEMS ;
  109. }
  110.  
  111. int LLDsystemInit( int ListCountInit )
  112. {
  113.     assert( (unsigned) ( ListCountInit -1 ) <= 20 -1 );
  114.                  /* negative is logic error (cast => neg. is large int) */
  115.                  /* higher than 20 is ridiculous for an initial setup   */
  116.                  /* zero is useless                                     */
  117.  
  118.     if( NULL != ListControl )
  119.     {
  120.         return NO_PROBLEMS ; /* LL system already initialized */
  121.     }
  122.  
  123.     ListControl = MALLOC( ListCountInit, struct ListHead );
  124.     if( NULL == ListControl )
  125.     {
  126.         return ERR_MEMORY ;
  127.     }
  128.  
  129.     for( ListCount = 0 ; ListCount < (unsigned)ListCountInit ; ListCount++ )
  130.         ListInit( ListCount, 0 ); /* just mark it as usable ... */
  131.  
  132.     /* ListCount is now ListCountInit */
  133.     assert( ListCount == (unsigned)ListCountInit );
  134.  
  135.     return NO_PROBLEMS;
  136. }
  137.  
  138. int LLDcreate( int ItemSize )
  139. {
  140.     int List ;
  141.  
  142.     assert( (unsigned) ( ItemSize -1 ) < 1024 -1 ) ;
  143.                              /* limit to 1kB. A size of 0 is ridiculous */
  144.  
  145.     /* trigger automatic system initialisation if neccesary
  146.     */
  147.     if( NULL == ListControl  &&  0 != LLDsystemInit( 1 ))
  148.     {
  149.         return ERR_MEMORY ;
  150.     }
  151.  
  152.     /* Look for empty slot
  153.     */
  154.     for( List = 0; List < (int)ListCount; List++ )
  155.     {
  156.         if( 0 == ListControl[ List ].itemsize )
  157.             break;
  158.     }
  159.  
  160.     /*  What if NO EMPTY slot ???
  161.     */
  162.     if( List == (int)ListCount )
  163.     {
  164.         struct ListHead * tmp ;         /* ListControl expansion needed */
  165.  
  166.         tmp = MALLOC( ListCount + 1, struct ListHead );
  167.         if( NULL == tmp )
  168.         {
  169.             return ERR_MEMORY ;
  170.         }
  171.  
  172.         memcpy( tmp, ListControl, ListCount * sizeof( struct ListHead ));
  173.         ListControl = tmp ;
  174.         ListCount++ ;
  175.     }
  176.  
  177.     /* create dummy head node and set up ListControl for the list.
  178.     */
  179.     if( ERR_MEMORY == ListInit( List, ItemSize ))
  180.     {
  181.         return ERR_MEMORY ;
  182.     }
  183.  
  184.     return List ;
  185. }
  186.  
  187. void LLDdelete( int List )
  188. {
  189.     struct Node * Tmp ;
  190.     struct Node * Old ;
  191.  
  192.     assert( (unsigned) List < ListCount );
  193.  
  194.     Tmp = ListControl[ List ].first ; /* dummies are also deleted !!!   */
  195.     while( NULL != Tmp )              /* still assuming last node has   */
  196.     {                                 /* a NULL next pointer ...        */
  197.         Old = Tmp ;
  198.         Tmp = Old->next;
  199.         NODE_FREE( Old ); /* data already presumed to be deleted */
  200.     }
  201.  
  202.     ListInit( List, 0 ); /* 0: mark list as not used. */
  203.  
  204.     return ;
  205. }
  206.  
  207. /* ---- LL system maintenance ----------------------------------------- */
  208.  
  209. int LLDcheck( int List )
  210. {
  211.     if( NULL == ListControl )
  212.     {
  213.         return LIST_SYSTEM_NULL ;
  214.     }
  215.  
  216.     if( (unsigned) List >= ListCount )
  217.     {
  218.         return LIST_INV_NUMBER ;
  219.     }
  220.  
  221.     if( 0 == ListControl[ List ].itemsize )
  222.     {
  223.         return LIST_NOT_CREATED ;
  224.     }
  225.  
  226.     if( NULL == ListControl[ List ].first
  227.         || NULL == ListControl[ List ].first->next    /* missing tail ? */
  228.         || NULL != ListControl[ List ].first->prev )
  229.     {
  230.         return LIST_ERR_HEAD ;
  231.     }
  232.  
  233.     /* Validate current pointer
  234.     */
  235.     if( NULL == ListControl[ List ].current )
  236.     {
  237.         return LIST_CORRUPT7 ;    /* shouldn't be NULL with a good head */
  238.     }
  239.  
  240.     if( NULL != ListControl[ List ].first->next->next ) /* empty list ? */
  241.     {                                                   /* not empty.   */
  242.         struct Node * tmp = ListControl[ List ].first ;
  243.  
  244.         if( NULL == ListControl[ List ].current->next )
  245.         {
  246.             return LIST_CORRUPT6 ; /* a NULL next pointer is only valid */
  247.         }                          /* for an empty list.                */
  248.  
  249.         /* look for .current in list,
  250.            checking the .prev links along the way
  251.         */
  252.         do
  253.         {
  254.             tmp = tmp->next ;
  255.  
  256.             if( NULL == tmp || NULL == tmp->prev
  257.                 || tmp != tmp->prev->next )
  258.             {
  259.                 return LIST_CORRUPT5 ;  /* current not found in list */
  260.             }                           /* or link to/from next node */
  261.                                         /* invalid                   */
  262.         }while( tmp != ListControl[ List ].current );
  263.  
  264.         /* Found .current in list. Also without link errors.
  265.            Now look for valid last node pointer in the list,
  266.            checking the .prev links along the way
  267.            Note that .current itself is never supposed to be equal
  268.            to .last (which points to the dummy tail) !
  269.         */
  270.         if( NULL == ListControl[ List ].last )
  271.         {
  272.             return LIST_ERR_LAST ;
  273.         }
  274.  
  275.         do
  276.         {
  277.             tmp = tmp->next ;
  278.             if( NULL == tmp || NULL == tmp->prev
  279.                 || tmp != tmp->prev->next )
  280.             {
  281.                 return LIST_CORRUPT4 ;  /* last not found in list    */
  282.             }                           /* or link to/from prev node */
  283.                                         /* invalid                   */
  284.         }while( tmp != ListControl[ List ].last );
  285.  
  286.         /* Found .last in list but is it really a valid last pointer?
  287.            Note: tmp == .last
  288.         */
  289.         if( NULL != tmp->next )
  290.         {
  291.             return LIST_CORRUPT3 ;
  292.         }
  293.  
  294.         return NO_PROBLEMS ;
  295.     }
  296.  
  297.     /* .first->next->next == NULL  =>  list is empty
  298.     */
  299.     if( ListControl[ List ].current != ListControl[ List ].first->next )
  300.     {
  301.         return LIST_CORRUPT2 ;
  302.     }
  303.  
  304.     if( ListControl[ List ].last != ListControl[ List ].first->next
  305.         || ListControl[ List ].last
  306.                              != ListControl[ List ].current->prev->next )
  307.     {
  308.         return LIST_CORRUPT1 ;
  309.     }
  310.  
  311.     return LIST_EMPTY ;
  312. }
  313.  
  314. /* ---- node management ----------------------------------------------- */
  315.  
  316. int LLDnodeInsert( int List, ... )      /* insert _BEFORE_ current node */
  317. {
  318.     va_list DataPtr ;
  319.     int Retval ;
  320.  
  321.     /* set DataPtr to the address of "..."
  322.        then action, cleanup and return.
  323.     */
  324.     va_start( DataPtr, List );
  325.  
  326.     Retval = LLDnodeInsertFrom( List, DataPtr );
  327.  
  328.     va_end( DataPtr );
  329.     return Retval ;
  330. }
  331.  
  332. int LLDnodeAdd( int List, ... )          /* insert _AFTER_ current node */
  333. {
  334.     va_list DataPtr ;
  335.     int Retval ;
  336.  
  337.     /* set DataPtr to the address of "..."
  338.        then action, cleanup and return.
  339.     */
  340.     va_start( DataPtr, List );
  341.  
  342.     Retval = LLDnodeAddFrom( List, DataPtr );
  343.  
  344.     va_end( DataPtr );
  345.     return Retval ;
  346. }
  347.  
  348. int LLDnodePrepend( int List, ... )             /* insert as first node */
  349. {
  350.     va_list DataPtr ;
  351.     int Retval ;
  352.  
  353.     /* set DataPtr to the address of "..."
  354.        then action, cleanup and return.
  355.     */
  356.     va_start( DataPtr, List );
  357.  
  358.     Retval = LLDnodePrependFrom( List, DataPtr );
  359.  
  360.     va_end( DataPtr );
  361.     return Retval ;
  362. }
  363.  
  364. int LLDnodeAppend( int List, ... )               /* insert as last node */
  365. {
  366.     va_list DataPtr ;
  367.     int Retval ;
  368.  
  369.     /* set DataPtr to the address of "..."
  370.        then action, cleanup and return.
  371.     */
  372.     va_start( DataPtr, List );
  373.  
  374.     Retval = LLDnodeAppendFrom( List, DataPtr );
  375.  
  376.     va_end( DataPtr );
  377.     return Retval ;
  378. }
  379.  
  380. int LLDnodeInsertFrom( int List, void * Source )
  381. {                                       /* insert _BEFORE_ current node */
  382.     struct Node * New ;
  383.  
  384.     assert( (unsigned) List < ListCount );
  385.  
  386.     /* create new node if possible
  387.     */
  388.     New = NODE_MALLOC( List );
  389.     if( NULL == New )
  390.     {
  391.         return ERR_MEMORY ;
  392.     }
  393.  
  394.     /* fill node with data, link to next and previous nodes
  395.        and adjust current node pointer
  396.     */
  397.     memcpy( & New->data, Source, ListControl[ List ].itemsize );
  398.     New->next = ListControl[ List ].current;
  399.     New->prev = ListControl[ List ].current->prev;
  400.  
  401.     ListControl[ List ].current->prev = New ;
  402.     New->prev->next = New ;
  403.  
  404.     ListControl[ List ].current = New ;
  405.  
  406.     return NO_PROBLEMS;
  407. }
  408.  
  409. int LLDnodeAddFrom( int List, void * Source )
  410. {                                        /* insert _AFTER_ current node */
  411.     struct Node * New ;
  412.  
  413.     assert( (unsigned) List < ListCount );
  414.  
  415.     /* create new node if possible
  416.     */
  417.     New = NODE_MALLOC( List );
  418.     if( NULL == New )
  419.     {
  420.         return ERR_MEMORY ;
  421.     }
  422.  
  423.     /* fill node with data and link to next and previous nodes
  424.        with special handling when the current node pointer points
  425.        to the dummy tail node: i.e it is an empty list.
  426.        (the same case in a non-empty list is made not to occur.)
  427.     */
  428.     memcpy( & New->data, Source, ListControl[ List ].itemsize );
  429.  
  430.     if( NULL != ListControl[ List ].current->next )
  431.         ListControl[ List ].current = ListControl[ List ].current->next ;
  432.  
  433.     New->next = ListControl[ List ].current;
  434.     New->prev = ListControl[ List ].current->prev;
  435.  
  436.     ListControl[ List ].current->prev = New ;
  437.     New->prev->next = New ;
  438.  
  439.     ListControl[ List ].current = New ;
  440.  
  441.     return NO_PROBLEMS;
  442. }
  443.  
  444. int LLDnodePrependFrom( int List, void * Source )
  445. {                                               /* insert as first node */
  446.     struct Node * New ;
  447.  
  448.     assert( (unsigned) List < ListCount );
  449.  
  450.     /* create new node if possible
  451.     */
  452.     New = NODE_MALLOC( List );
  453.     if( NULL == New )
  454.     {
  455.         return ERR_MEMORY ;
  456.     }
  457.  
  458.     /* fill node with data and link to dummy head and actual first nodes
  459.     */
  460.     memcpy( & New->data, Source, ListControl[ List ].itemsize );
  461.     New->prev = ListControl[ List ].first;     /* == .first->next->prev */
  462.     New->next = ListControl[ List ].first->next;
  463.  
  464.     ListControl[ List ].first->next = New;
  465.     New->next->prev = New ;
  466.  
  467.     /* Prevent .current from pointing at the dummy tail
  468.        (New is the only normal node...)
  469.     */
  470.     if( NULL == ListControl[ List ].current->next )
  471.         ListControl[ List ].current = New;
  472.  
  473.     return NO_PROBLEMS;
  474. }
  475.  
  476. int LLDnodeAppendFrom( int List, void * Source )
  477. {                                                /* insert as last node */
  478.     struct Node * New ;
  479.  
  480.     assert( (unsigned) List < ListCount );
  481.  
  482.     /* create new node if possible
  483.     */
  484.     New = NODE_MALLOC( List );
  485.     if( NULL == New )
  486.     {
  487.         return ERR_MEMORY ;
  488.     }
  489.  
  490.     /* fill node with data and link to dummy tail and actual last nodes
  491.     */
  492.     memcpy( & New->data, Source, ListControl[ List ].itemsize );
  493.     New->next = ListControl[ List ].last ;      /* == .last->prev->next */
  494.     New->prev = ListControl[ List ].last->prev;
  495.  
  496.     ListControl[ List ].last->prev = New ;
  497.     New->prev->next = New ;
  498.  
  499.     /* Prevent .current from pointing at the dummy tail
  500.        (New is the only normal node...)
  501.     */
  502.     if( NULL == ListControl[ List ].current->next )
  503.         ListControl[ List ].current = New;
  504.  
  505.     return NO_PROBLEMS;
  506. }
  507.  
  508. void LLDnodeDelete( int List )
  509. {
  510.     struct Node * Old = ListControl[ List ].current ;
  511.  
  512.     assert( (unsigned) List < ListCount );
  513.  
  514.     if( NULL == ListControl[ List ].current->next )
  515.     {
  516.         return ;  /* don't delete dummy tail node (list is empty) */
  517.     }
  518.  
  519.     /* adjust links
  520.     */
  521.     Old->prev->next = Old->next ;
  522.     Old->next->prev = Old->prev ;
  523.  
  524.     /* adjust current node pointer
  525.        prevent it from pointing to the dummy tail node
  526.     */
  527.     if( NULL != Old->next->next )
  528.         ListControl[ List ].current = Old->next ;
  529.     else
  530.         ListControl[ List ].current = Old->prev ;
  531.  
  532.     NODE_FREE( Old );
  533.  
  534.     return ;
  535. }
  536.  
  537. int LLDnodeFind( int List, CompFunPtr Compare, void * DataPtr )
  538. {                        /* FindFirst/FindNext format may be needed ... */
  539.     int RetVal ;
  540.  
  541.     assert( (unsigned) List < ListCount );
  542.  
  543.     if( NULL == ListControl[ List ].first->next->next ) /* empty list ? */
  544.     {
  545.         return 2; /* a compare usually returns just -1, 0 or 1 !!! */
  546.     }
  547.  
  548.     /* note: current->next will never be NULL in a non-empty list */
  549.  
  550.     if( NULL == Compare ) /* default to memcmp with .itemsize */
  551.     {
  552.         while( 0 != (RetVal = memcmp( DataPtr,
  553.                                       & ListControl[ List ].current->data,
  554.                                       ListControl[ List ].itemsize ))
  555.                && NULL != ListControl[ List ].current->next->next )
  556.         {
  557.             ListControl[ List ].current=ListControl[ List ].current->next;
  558.         }
  559.         return RetVal ;
  560.     }
  561.     else
  562.     {
  563.         while( 0 != (RetVal = (*Compare)( DataPtr,
  564.                                    & ListControl[ List ].current->data ))
  565.                && NULL != ListControl[ List ].current->next->next )
  566.         {
  567.             ListControl[ List ].current=ListControl[ List ].current->next;
  568.         }
  569.         return RetVal ;
  570.     }
  571. }
  572.  
  573. /* ---- current node pointer management ------------------------------- */
  574.  
  575. int  LLDnodePtr2First( int List )
  576. {
  577.     assert( (unsigned) List < ListCount );
  578.  
  579.     ListControl[ List ].current = ListControl[ List ].first->next ;
  580.  
  581.     return NULL != ListControl[ List ].first->next->next ;
  582. }
  583.  
  584. int  LLDnodePtr2Last( int List )
  585. {
  586.     assert( (unsigned) List < ListCount );
  587.  
  588.     ListControl[ List ].current = ListControl[ List ].last->prev ;
  589.  
  590.     return NULL != ListControl[ List ].last->prev->prev ;
  591. }
  592.  
  593. int  LLDnodePtr2Next( int List )
  594. {
  595.     assert( (unsigned) List < ListCount );
  596.  
  597.     if( NULL == ListControl[ List ].current->next       /* empty list ? */
  598.         || NULL == ListControl[ List ].current->next->next ) /* at end ?*/
  599.     {
  600.         return 0 ;             /* do not allow the current node pointer */
  601.     }                          /* to point at the dummy tail node ...   */
  602.  
  603.     ListControl[ List ].current = ListControl[ List ].current->next ;
  604.     return 1 ;
  605. }
  606.  
  607. int  LLDnodePtr2Prev( int List )
  608. {
  609.     assert( (unsigned) List < ListCount );
  610.  
  611.     if( NULL == ListControl[ List ].current->prev       /* empty list ? */
  612.         || NULL == ListControl[ List ].current->prev->prev ) /* begin ? */
  613.     {
  614.         return 0 ;             /* do not allow the current node pointer */
  615.     }                          /* to point at the dummy head node ...   */
  616.  
  617.     ListControl[ List ].current = ListControl[ List ].current->prev ;
  618.     return 1 ;
  619. }
  620.  
  621. /* ---- stored data management ---------------------------------------- */
  622.  
  623. int LLDnodeInt( int List )
  624. {
  625.     return ListControl[ List ].current->data;
  626. }
  627.  
  628. long LLDnodeLong( int List )
  629. {
  630.     return *((long *) &ListControl[ List ].current->data );
  631. }
  632.  
  633. void * LLDnodePtr( int List )
  634. {
  635.     return *((void **) &ListControl[ List ].current->data );
  636. }
  637.  
  638. void FAR * LLDnodeFptr( int List )
  639. {
  640.     return *((void FAR **) &ListControl[ List ].current->data );
  641. }
  642.  
  643. int LLDnodeDataTo( int List, void * Destination )
  644. {
  645.     if( NULL != Destination )
  646.     {
  647.         memcpy( Destination,
  648.                 & ListControl[ List ].current->data,
  649.                 ListControl[ List ].itemsize );
  650.     }
  651.  
  652.     return ListControl[ List ].itemsize ;       /* size needed for blob */
  653. }
  654.  
  655. /* ==== LLD.c  end ==================================================== */
  656.